
// === uuMeta.msgpump ===
// depend: uuMeta
/*
uuMeta.msgpump.prototype.regist(obj, ...) - return this
uuMeta.msgpump.prototype.unregist(obj, ...) - return this
uuMeta.msgpump.prototype.send(to, msg, p1, p2) - return msgbox() result value
uuMeta.msgpump.prototype.post(to, msg, p1, p2) - return this
 */
(function uuMetaMsgPumpScope() {

function msgpump() {
  this._addr = { /* unique-id: obj, ... */ };
  this._msg = [ /* num: [ unique-id, msg, param1, param2], ... */ ];
  this._run = 0;
}

// uuMeta.msgpump.prototype.regist - register the destination of the message
function regist(obj,        // @param Object: object has uuqid property
                var_args) { // @param Object(= undefined):
                            // @return this:
  var arg = arguments, v, i = 0, iz = arg.length;

  for (; i < iz; ++i) {
    v = arg[i];
    if (!v.uuqid) { throw ""; }
    this._addr[v.uuqid] = v;
  }
  return this;
}

// uuMeta.msgpump.prototype.unregist
function unregist(obj,        // @param Object: object has uuqid property
                  var_args) { // @param Object(= undefined):
                              // @return this:
  var arg = arguments, v, i = 0, iz = arg.length;

  for (; i < iz; ++i) {
    v = arg[i];
    if (!v.uuqid) { throw ""; }
    delete this._addr[obj.uuqid];
  }
  return this;
}

// uuMeta.msgpump.prototype.send - send a message synchronously
function send(to,   // @param Object: send to
              msg,  // @param String: msg
              p1,   // @param Mix(= undefined): param1
              p2) { // @param Mix(= undefined): param2
                    // @return Mix: msgbox() result value
  var rv = [], v, i, iz, ary;

  if (to) { // unicast, multicast
    ary = (to instanceof Array) ? to : [to];
    for (i = 0, iz = ary.length; i < iz; ++i) {
      v = ary[i];
      rv.push(this._addr[typeof v === "object" ? v.uuqid
                                               : v].msgbox(msg, p1, p2));
    }
    // if it is an unicast, not the array but the return value is returned.
    return (rv.length === 1) ? rv[0] : rv;
  }
  // broadcast
  for (i in this._addr) {
    rv.push(this._addr[i].msgbox(msg, p1, p2));
  }
  return rv;
}

// uuMeta.msgpump.prototype.post - send a message asynchronously
function post(to,   // @param Object: send to
              msg,  // @param String: msg
              p1,   // @param Mix(= undefined): param1
              p2) { // @param Mix(= undefined): param2
                    // @return this:
  var stock = this._msg, v, i, iz, ary;

  if (to) { // unicast, multicast
    ary = (to instanceof Array) ? to : [to];
    for (i = 0, iz = ary.length; i < iz; ++i) {
      v = ary[i];
      stock.push([typeof v === "object" ? v.uuqid : v, msg, p1, p2]);
    }
  } else { // broadcast
    for (i in this._addr) {
      stock.push([i, msg, p1, p2]);
    }
  }
  runner(this);
  return this;
}

// inner -
function runner(me) {
  function loop() {
    if (!me._msg.length) {
      me._run = 0;
      return;
    }
    var v = me._msg.shift();

    if (v[0] in me._addr) {
      me._addr[v[0]].msgbox(v[1], v[2], v[3]); // (msg, param1, param2)
    }
    me._run = 1;
    setTimeout(loop, 0);
  };

  !me._run && loop();
}

// --- initialize ---

// --- export ---
msgpump.prototype = {
  regist: regist,
  unregist: unregist,
  send: send,
  post: post
};

uuMeta.msg = new msgpump(); // uuMeta.msg instance

})(); // uuMeta.msgpump scope

